package com.hd.quartz.util;

import com.hd.quartz.entity.ScheduleJobEntity;
import com.hd.quartz.exception.RRException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.quartz.*;

/**
 * <h3>partitionjob</h3>
 * <p>ScheduleUtils</p>
 *
 * @author : hduong
 * @version : 1.0
 * @date : 2020-09-11 16:19
 **/
@Slf4j
public class ScheduleUtils {

    private final static String JOB_NAME = "TASK_";


    /**
     * 获取触发器key
     *
     * @param jobId
     */
    public static TriggerKey getTriggerKey(Long jobId) {
        return TriggerKey.triggerKey(JOB_NAME + jobId);
    }

    /**
     * 获取jobKey
     */
    public static JobKey getJobKey(Long jobId) {
        return JobKey.jobKey(JOB_NAME + jobId);
    }


    /**
     * 获取表达式触发器
     */
    public static CronTrigger getCronTrigger(Scheduler scheduler, Long jobId) {
        try {
            return (CronTrigger) scheduler.getTrigger(getTriggerKey(jobId));
        } catch (SchedulerException e) {
            throw new RRException("获取定时任务CronTrigger出现异常", e);
        }

    }

    /**
     * 1: 根据 任务实体类 创建任务
     * 2:  任务实体类通过查询数据库初始化获取
     *
     * @param scheduler
     * @param jobEntity
     */
    public static void createScheduleJob(Scheduler scheduler, ScheduleJobEntity jobEntity) {
        //1: 构建 job 信息
        //2: 表达式构建器
        //3: 根据新的 cron 表达式构建一个新的trigger
        //4: 放入参数 : 运行时可以在执行上下文中获取
        //5: 暂停任务 : 根据状态判断
        try {
            JobDetail jobDetail = JobBuilder.newJob(ScheduleJob.class)
                    .withIdentity(getJobKey(jobEntity.getJobId()))
                    .build();
            CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(jobEntity.getCronExpression())
                    .withMisfireHandlingInstructionDoNothing();

            CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity(getTriggerKey(jobEntity.getJobId()))
                    .withSchedule(scheduleBuilder)
                    .build();
            //构建任务时 设置了key
            jobDetail.getJobDataMap().put(ScheduleJobEntity.JOB_PARAM_KEY, jobEntity);
            //如果是批量任务 : 根据 名字 获取bean
            if(jobEntity.getStatus() != null && jobEntity.getIsBatchJob() == 1) {
                jobDetail.getJobDataMap().put(ScheduleJobEntity.BATCH_JOB_KEY, jobEntity.getBeanName());
            }

            scheduler.scheduleJob(jobDetail, cronTrigger);

            if(jobEntity.getStatus() != null && jobEntity.getStatus() == Constant.ScheduleStatus.PAUSE.getValue()) {
                pauseJob(scheduler, jobEntity.getJobId());
            }

        } catch (SchedulerException e) {
            throw new RRException("创建定时任务失败", e);
        }
    }


    /**
     *
     * @param scheduler
     * @param jobId
     */
    public static void pauseJob(Scheduler scheduler, Long jobId) {
        try {
            scheduler.pauseJob(getJobKey(jobId));
        } catch (SchedulerException e) {
            throw new RRException("暂停定时任务失败", e);
        }
    }

    /**
     * 更新定时任务
     * @param scheduler
     * @param entity
     */
    public static void updateScheduleJob(Scheduler scheduler, ScheduleJobEntity entity) {

        try {

            TriggerKey triggerKey = getTriggerKey(entity.getJobId());

            //表达式调度构建器
            CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(entity.getCronExpression())
                    .withMisfireHandlingInstructionDoNothing();
            CronTrigger trigger = getCronTrigger(scheduler, entity.getJobId());

            //按新的cronExpression表达式重新构建trigger
            trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();

            //参数
            trigger.getJobDataMap().put(ScheduleJobEntity.JOB_PARAM_KEY, entity);
            //如果是批量任务 : 根据 名字 获取bean
            if(entity.getStatus() != null && entity.getIsBatchJob() == 1) {
                String beanName = entity.getBeanName();
                Object object = SpringContextUtil.getBean(beanName);
                log.info("根据beanName: {}, 获取bean对象: {}", beanName, object);
                trigger.getJobDataMap().put(ScheduleJobEntity.BATCH_JOB_KEY, object);
                trigger.getJobDataMap().put(ScheduleJobEntity.BATCH_JOB_LAUNCHER_KEY, SpringContextUtil.getBean(ScheduleJobEntity.BATCH_JOB_LAUNCHER_KEY));
            }

            scheduler.rescheduleJob(triggerKey, trigger);

            //暂停任务
            if(entity.getStatus() != null && entity.getStatus() == Constant.ScheduleStatus.PAUSE.getValue()){
                pauseJob(scheduler, entity.getJobId());
            }

        } catch (SchedulerException e) {
            throw new RRException("更新定时任务失败", e);
        }
    }

    /**
     * 删除 定时任务
     * @param scheduler
     * @param id
     */
    public static void deleteScheduleJob(Scheduler scheduler, Long id) {
        try {
            scheduler.deleteJob(getJobKey(id));
        } catch (SchedulerException e) {
         throw new RRException("删除定时任务失败", e);
        }
    }
    //*********************立即执行任务
    //*********************暂停任务
    //*********************恢复任务
    public static void run(Scheduler scheduler, ScheduleJobEntity jobEntity) {
        try{
                //1: 立即执行
            JobDataMap jobDataMap = new JobDataMap();
            jobDataMap.put(ScheduleJobEntity.JOB_PARAM_KEY, jobEntity);

            scheduler.triggerJob(getJobKey(jobEntity.getJobId()), jobDataMap);
        } catch (Exception e) {
            throw new RRException("立即执行定时任务失败", e);
        }
    }

    /**
     * 恢复 定时任务
     * @param scheduler
     * @param jobEntity
     */
    public static void resumeJob(Scheduler scheduler, ScheduleJobEntity jobEntity) {
        try {
            scheduler.resumeJob(getJobKey(jobEntity.getJobId()));
        } catch (SchedulerException e) {
            throw new RRException("恢复定时任务失败", e);
        }
    }

}
